"""
用户管理服务
提供用户账户管理、密码策略验证、权限控制等功能
"""
import re
import secrets
import string
from typing import List, Optional, Dict, Any, Tuple
from datetime import datetime, timedelta
from sqlalchemy.orm import Session
from sqlalchemy import or_, and_, func

from models.user import User
from core.logging_config import get_logger
from core.exceptions import ValidationError, DataNotFoundError, DataAlreadyExistsError, AuthorizationError
from services.security_service import SecurityEventType, security_auditor

# 日志记录器
logger = get_logger("user_management_service")

# 强制重新加载模块以解决导入问题


class PasswordPolicy:
    """密码策略配置"""
    MIN_LENGTH = 8
    MAX_LENGTH = 128
    REQUIRE_UPPERCASE = True
    REQUIRE_LOWERCASE = True
    REQUIRE_DIGITS = True
    REQUIRE_SPECIAL = True
    FORBIDDEN_PATTERNS = [
        r'password', r'123456', r'qwerty', r'abc123', 
        r'admin', r'user', r'test', r'default'
    ]
    FORBIDDEN_SEQUENCES = ['123', 'abc', 'qwerty', 'asdf']


class UserManagementService:
    """用户管理服务类"""
    
    def __init__(self, db: Session):
        self.db = db
        self.security_auditor = security_auditor
    
    def validate_password(self, password: str, username: str = None) -> Tuple[bool, str]:
        """
        验证密码强度
        
        Args:
            password: 要验证的密码
            username: 用户名（用于检查密码中是否包含用户名）
            
        Returns:
            Tuple[bool, str]: (是否通过验证, 错误信息)
        """
        # 检查长度
        if len(password) < PasswordPolicy.MIN_LENGTH:
            return False, f"密码长度不能少于{PasswordPolicy.MIN_LENGTH}个字符"
        if len(password) > PasswordPolicy.MAX_LENGTH:
            return False, f"密码长度不能超过{PasswordPolicy.MAX_LENGTH}个字符"
        
        # 检查是否包含用户名
        if username and username.lower() in password.lower():
            return False, "密码不能包含用户名"
        
        # 检查大写字母
        if PasswordPolicy.REQUIRE_UPPERCASE and not re.search(r'[A-Z]', password):
            return False, "密码必须包含大写字母"
        
        # 检查小写字母
        if PasswordPolicy.REQUIRE_LOWERCASE and not re.search(r'[a-z]', password):
            return False, "密码必须包含小写字母"
        
        # 检查数字
        if PasswordPolicy.REQUIRE_DIGITS and not re.search(r'\d', password):
            return False, "密码必须包含数字"
        
        # 检查特殊字符
        if PasswordPolicy.REQUIRE_SPECIAL and not re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
            return False, "密码必须包含特殊字符"
        
        # 检查禁止的密码模式
        password_lower = password.lower()
        for pattern in PasswordPolicy.FORBIDDEN_PATTERNS:
            if pattern in password_lower:
                return False, f"密码不能包含常见词汇: {pattern}"
        
        # 检查连续序列
        for sequence in PasswordPolicy.FORBIDDEN_SEQUENCES:
            if sequence in password_lower:
                return False, f"密码不能包含连续序列: {sequence}"
        
        # 检查重复字符
        if len(set(password)) < len(password) * 0.5:
            return False, "密码字符重复度过高"
        
        return True, "密码强度验证通过"
    
    def generate_strong_password(self, length: int = 12) -> str:
        """
        生成强密码
        
        Args:
            length: 密码长度，默认12位
            
        Returns:
            str: 生成的强密码
        """
        # 确保密码包含所有必需的字符类型
        uppercase = string.ascii_uppercase
        lowercase = string.ascii_lowercase
        digits = string.digits
        special = "!@#$%^&*"
        
        # 构建字符池
        all_chars = uppercase + lowercase + digits + special
        
        # 生成密码
        password = []
        # 确保至少包含一个大写字母
        password.append(secrets.choice(uppercase))
        # 确保至少包含一个小写字母
        password.append(secrets.choice(lowercase))
        # 确保至少包含一个数字
        password.append(secrets.choice(digits))
        # 确保至少包含一个特殊字符
        password.append(secrets.choice(special))
        
        # 填充剩余长度
        remaining_length = length - 4
        if remaining_length > 0:
            for _ in range(remaining_length):
                password.append(secrets.choice(all_chars))
        
        # 打乱顺序
        secrets.SystemRandom().shuffle(password)
        
        return ''.join(password)
    
    def get_users(self, 
                  page: int = 1, 
                  size: int = 10, 
                  search: str = None, 
                  role: str = None,
                  is_active: bool = None) -> Dict[str, Any]:
        """
        获取用户列表
        
        Args:
            page: 页码
            size: 每页数量
            search: 搜索关键词
            role: 角色过滤
            is_active: 激活状态过滤
            
        Returns:
            Dict: 包含用户列表和分页信息
        """
        # 构建查询
        query = self.db.query(User).filter(User.is_deleted == False)
        
        # 搜索条件
        if search:
            query = query.filter(
                or_(
                    User.username.contains(search),
                    User.email.contains(search),
                    User.full_name.contains(search),
                    User.phone.contains(search)
                )
            )
        
        # 角色过滤
        if role:
            query = query.filter(User.role == role)
        
        # 激活状态过滤
        if is_active is not None:
            query = query.filter(User.is_active == is_active)
        
        # 获取总数
        total = query.count()
        
        # 分页查询
        offset = (page - 1) * size
        users = query.order_by(User.created_at.desc()).offset(offset).limit(size).all()
        
        return {
            "users": users,
            "total": total,
            "page": page,
            "size": size,
            "total_pages": (total + size - 1) // size
        }
    
    def get_user_by_id(self, user_id: int) -> Optional[User]:
        """
        根据ID获取用户
        
        Args:
            user_id: 用户ID
            
        Returns:
            Optional[User]: 用户对象或None
        """
        return self.db.query(User).filter(
            User.id == user_id,
            User.is_deleted == False
        ).first()
    
    def create_user(self, 
                   username: str, 
                   email: str, 
                   password: str,
                   full_name: str = None,
                   phone: str = None,
                   role: str = "user",
                   created_by: User = None) -> User:
        """
        创建用户
        
        Args:
            username: 用户名
            email: 邮箱
            password: 密码
            full_name: 全名
            phone: 电话
            role: 角色
            created_by: 创建者
            
        Returns:
            User: 创建的用户对象
        """
        # 验证密码强度
        is_valid, error_msg = self.validate_password(password, username)
        if not is_valid:
            raise ValidationError(error_msg)
        
        # 检查用户名是否已存在
        existing_user = self.db.query(User).filter(
            User.username == username,
            User.is_deleted == False
        ).first()
        if existing_user:
            raise DataAlreadyExistsError("用户名已存在")
        
        # 检查邮箱是否已存在
        existing_email = self.db.query(User).filter(
            User.email == email,
            User.is_deleted == False
        ).first()
        if existing_email:
            raise DataAlreadyExistsError("邮箱已存在")
        
        # 创建用户
        user = User(
            username=username,
            email=email,
            password=password,  # 会自动进行哈希处理
            full_name=full_name,
            phone=phone,
            role=role
        )
        
        self.db.add(user)
        self.db.flush()  # 获取用户ID
        
        # 记录安全审计日志
        if created_by:
            self.security_auditor.log_security_event(
                SecurityEventType.SYSTEM_CONFIG_CHANGE,
                f"创建用户: {username}",
                created_by.id,
                {"user_id": user.id, "username": username, "role": role}
            )
        
        self.db.commit()
        self.db.refresh(user)
        
        logger.info(f"创建用户成功: {username}")
        return user
    
    def update_user(self, 
                   user_id: int, 
                   email: str = None,
                   full_name: str = None,
                   phone: str = None,
                   role: str = None,
                   is_active: bool = None,
                   updated_by: User = None) -> User:
        """
        更新用户信息
        
        Args:
            user_id: 用户ID
            email: 邮箱
            full_name: 全名
            phone: 电话
            role: 角色
            is_active: 激活状态
            updated_by: 更新者
            
        Returns:
            User: 更新后的用户对象
        """
        user = self.get_user_by_id(user_id)
        if not user:
            raise DataNotFoundError("用户不存在")
        
        # 检查邮箱是否已被其他用户使用
        if email and email != user.email:
            existing_email = self.db.query(User).filter(
                User.email == email,
                User.id != user_id,
                User.is_deleted == False
            ).first()
            if existing_email:
                raise DataAlreadyExistsError("邮箱已被其他用户使用")
        
        # 记录变更前后的值
        changes = {}
        if email and email != user.email:
            changes["email"] = {"old": user.email, "new": email}
            user.email = email
        if full_name is not None and full_name != user.full_name:
            changes["full_name"] = {"old": user.full_name, "new": full_name}
            user.full_name = full_name
        if phone is not None and phone != user.phone:
            changes["phone"] = {"old": user.phone, "new": phone}
            user.phone = phone
        if role is not None and role != user.role:
            changes["role"] = {"old": user.role, "new": role}
            user.role = role
        if is_active is not None and is_active != user.is_active:
            changes["is_active"] = {"old": user.is_active, "new": is_active}
            user.is_active = is_active
        
        if changes and updated_by:
            self.security_auditor.log_security_event(
                SecurityEventType.SYSTEM_CONFIG_CHANGE,
                f"更新用户信息: {user.username}",
                updated_by.id,
                {"user_id": user_id, "changes": changes}
            )
        
        self.db.commit()
        self.db.refresh(user)
        
        logger.info(f"更新用户成功: {user.username}")
        return user
    
    def delete_user(self, user_id: int, deleted_by: User = None) -> bool:
        """
        删除用户（软删除）
        
        Args:
            user_id: 用户ID
            deleted_by: 删除者
            
        Returns:
            bool: 删除是否成功
        """
        user = self.get_user_by_id(user_id)
        if not user:
            raise DataNotFoundError("用户不存在")
        
        # 不能删除超级用户
        if user.is_superuser:
            raise ValidationError("不能删除超级用户")
        
        # 不能删除自己
        if deleted_by and deleted_by.id == user_id:
            raise ValidationError("不能删除自己")
        
        # 软删除
        user.soft_delete()
        
        # 记录安全审计日志
        if deleted_by:
            self.security_auditor.log_security_event(
                SecurityEventType.SYSTEM_CONFIG_CHANGE,
                f"删除用户: {user.username}",
                deleted_by.id,
                {"user_id": user_id, "username": user.username}
            )
        
        self.db.commit()
        
        logger.info(f"删除用户成功: {user.username}")
        return True
    
    def reset_password(self, user_id: int, reset_by: User = None) -> str:
        """
        重置用户密码
        
        Args:
            user_id: 用户ID
            reset_by: 重置者
            
        Returns:
            str: 新生成的密码
        """
        user = self.get_user_by_id(user_id)
        if not user:
            raise DataNotFoundError("用户不存在")
        
        # 生成强密码
        new_password = self.generate_strong_password()
        
        # 设置新密码
        user.set_password(new_password)
        
        # 清除重置令牌（如果有）
        user.clear_reset_token()
        
        # 记录安全审计日志
        if reset_by:
            self.security_auditor.log_security_event(
                SecurityEventType.PASSWORD_CHANGE,
                f"重置用户密码: {user.username}",
                reset_by.id,
                {"user_id": user_id, "username": user.username}
            )
        
        self.db.commit()
        
        logger.info(f"重置用户密码成功: {user.username}")
        return new_password
    
    def change_password(self, 
                      user_id: int, 
                      current_password: str, 
                      new_password: str,
                      changed_by: User = None) -> bool:
        """
        修改用户密码
        
        Args:
            user_id: 用户ID
            current_password: 当前密码
            new_password: 新密码
            changed_by: 修改者
            
        Returns:
            bool: 修改是否成功
        """
        user = self.get_user_by_id(user_id)
        if not user:
            raise DataNotFoundError("用户不存在")
        
        # 验证当前密码
        if not user.verify_password(current_password):
            raise ValidationError("当前密码错误")
        
        # 验证新密码强度
        is_valid, error_msg = self.validate_password(new_password, user.username)
        if not is_valid:
            raise ValidationError(error_msg)
        
        # 检查新密码是否与当前密码相同
        if user.verify_password(new_password):
            raise ValidationError("新密码不能与当前密码相同")
        
        # 设置新密码
        user.set_password(new_password)
        
        # 清除重置令牌（如果有）
        user.clear_reset_token()
        
        # 记录安全审计日志
        operator_id = changed_by.id if changed_by else user_id
        self.security_auditor.log_security_event(
            SecurityEventType.PASSWORD_CHANGE,
            f"修改用户密码: {user.username}",
            operator_id,
            {"user_id": user_id, "username": user.username}
        )
        
        self.db.commit()
        
        logger.info(f"修改用户密码成功: {user.username}")
        return True
    
    def get_user_statistics(self) -> Dict[str, Any]:
        """
        获取用户统计信息
        
        Returns:
            Dict: 用户统计数据
        """
        # 总用户数
        total_users = self.db.query(User).filter(User.is_deleted == False).count()
        
        # 活跃用户数
        active_users = self.db.query(User).filter(
            User.is_deleted == False,
            User.is_active == True
        ).count()
        
        # 按角色统计
        role_stats = self.db.query(
            User.role,
            func.count(User.id).label('count')
        ).filter(
            User.is_deleted == False
        ).group_by(User.role).all()
        
        # 今日新增用户
        from datetime import date
        today_new = self.db.query(User).filter(
            User.is_deleted == False,
            func.date(User.created_at) == date.today()
        ).count()
        
        # 最近7天新增用户
        from datetime import timedelta
        week_ago = date.today() - timedelta(days=7)
        week_new = self.db.query(User).filter(
            User.is_deleted == False,
            func.date(User.created_at) >= week_ago
        ).count()
        
        return {
            "total_users": total_users,
            "active_users": active_users,
            "inactive_users": total_users - active_users,
            "role_statistics": {role: count for role, count in role_stats},
            "today_new": today_new,
            "week_new": week_new
        }